/*
 * main.c
 *
 *  Created on: 29/09/2011
 *      Author: Power Rangers Turbo C
 */
#include "cola.h"
#include <stdlib.h>
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/select.h>
#include <sys/types.h>

#define CANTIDAD_DISCOS 3
enum estados {
	ACTIVO = 1, INACTIVO = 2
};
typedef struct infoDsico {
	int estadoPDD;
	int identificador;
	int pedidosEnCola;
	int yaReflejado; //es un booleano
	pthread_t* tid; //tid del thread asignado al disco
	int descriptorSocketPDD;
	cola_NODO* pedidosAEnviar;
} DISCO;

void pdd_thread(void *arg);

int main() {
	DISCO* discoTrabajo;
	//para el select
	fd_set descriptoresParaLeer;
	fd_set descriptoresParaEscribir;
	fd_set descriptoresExcep;
	int numeroDescriptorMaximo = 0;
	FD_ZERO(&descriptoresParaLeer);
	FD_ZERO(&descriptoresParaEscribir);
	FD_ZERO(&descriptoresExcep);
	//General del RAID
	int cantidadDiscosConectados = 0;
	DISCO* discos = (DISCO*) malloc(sizeof(DISCO) * CANTIDAD_DISCOS); //vector con los datos de cada PDD
	int estadoPRAID = INACTIVO;
	cola *colaEntrada;
	colaEntrada = MALLOC_COLA;
	cola_inicializacionCola(colaEntrada);
	PEDIDO* ped;

	//SOCKET PARA SER SERVIDOR
	int addrlen = sizeof(struct sockaddr_in);
	char buffer[100];

	/* Creo el socket TCP */
	int descriptorServidorPFS = socket(AF_INET, SOCK_STREAM, 0);
	int descriptorServidorPDD = socket(AF_INET, SOCK_STREAM, 0);
	int descriptorPFS;
	/*Direccion local*/
	struct sockaddr_in *direccionLocalParaPFS = malloc(
			sizeof(struct sockaddr_in));
	struct sockaddr_in *direccionLocalParaPDD = malloc(
			sizeof(struct sockaddr_in));
	/*Direccion remota (a la que me quiero conectar)*/
	struct sockaddr_in *direccionPFS = malloc(sizeof(struct sockaddr_in));
	{
		numeroDescriptorMaximo = descriptorServidorPFS;
		if (descriptorServidorPDD > numeroDescriptorMaximo) {
			numeroDescriptorMaximo = descriptorServidorPDD;
		}
		direccionLocalParaPFS->sin_family = AF_INET;
		direccionLocalParaPFS->sin_addr.s_addr = inet_addr("127.0.0.1");
		direccionLocalParaPFS->sin_port = htons(5200); //PUERTO DE ESCUCHA VA POR ARCHIVO CONFIG PUERTO_ESCUCHA_PFS
		/*Le asigno la direccion al socket, le doy nombre*/
		bind(descriptorServidorPFS, (struct sockaddr *) direccionLocalParaPFS,
				sizeof(struct sockaddr_in));
		direccionLocalParaPDD->sin_family = AF_INET;
		direccionLocalParaPDD->sin_addr.s_addr = inet_addr("127.0.0.1");
		direccionLocalParaPDD->sin_port = htons(5201); //PUERTO DE ESCUCHA VA POR ARCHIVO CONFIG PUERTO_ESCUCHA_PDD
		/*Le asigno la direccion al socket, le doy nombre*/
		bind(descriptorServidorPDD, (struct sockaddr *) direccionLocalParaPDD,
				sizeof(struct sockaddr_in));
	}

	/*Activo la escucha de direcciones entrantes*/
	listen(descriptorServidorPFS, 1);/*Encola conexiones que llegan al socket descripto por descriptorServidorPFS en una cola de 1*/
	listen(descriptorServidorPDD, 100);

	FD_SET(descriptorServidorPFS, &descriptoresParaLeer); //meto en el set el socket del servidorPFS
	FD_SET(descriptorServidorPDD, &descriptoresParaLeer);

	while (1) {

		fd_set descriptoresParaLeerCopia = descriptoresParaLeer;
		fd_set descriptoresParaEscribirCopia = descriptoresParaEscribir;
		fd_set descriptoresExcepCopia = descriptoresExcep;
		int numeroMaximoDeTrabajo = numeroDescriptorMaximo + 1;
		select(numeroMaximoDeTrabajo, &descriptoresParaLeerCopia,
				&descriptoresParaEscribirCopia, &descriptoresExcepCopia, NULL);
		if (FD_ISSET(descriptorServidorPFS, &descriptoresParaLeerCopia)) {
			//HAGO ESTO HASTA QUE ESTE ACTIVO EL RAID y haya aceptado al PFS
			//Acepto conexion de PFS
			descriptorPFS = accept(descriptorServidorPFS,
					(struct sockaddr *) direccionPFS,
					(socklen_t*) sizeof(struct sockaddr_in));
			//me fijo si esta activo el RAID
			/*hago handshake y si no esta activo el RAID le informo y cierro conexion*/
			{ //esto lo hago si ya se puede aceptar al PFS
				FD_SET(descriptorPFS, &descriptoresParaLeer);
				FD_SET(descriptorPFS, &descriptoresParaEscribir);
				FD_SET(descriptorPFS, &descriptoresExcep);

				if (descriptorPFS > numeroDescriptorMaximo) {
					numeroDescriptorMaximo = descriptorPFS;
				}
			}
		}
		if (FD_ISSET(descriptorServidorPDD, &descriptoresParaLeerCopia)) {
			discos[cantidadDiscosConectados].descriptorSocketPDD = accept(
					descriptorServidorPFS, (struct sockaddr *) direccionPFS,
					(socklen_t*) sizeof(struct sockaddr_in));

			//lanzo thread para este disco y el thread tiene que meter en una cola general de PEDIDOS_RESUELTOS y mandar pedidos al PDD
			//hago el handshake
			/*FD_SET(discos[cantidadDiscosConectados].descriptorSocketPDD,
					&descriptoresParaLeer);
			FD_SET(discos[cantidadDiscosConectados].descriptorSocketPDD,
					&descriptoresParaEscribir);
			FD_SET(discos[cantidadDiscosConectados].descriptorSocketPDD,
					&descriptoresExcep);
			if (discos[cantidadDiscosConectados].descriptorSocketPDD
					> numeroDescriptorMaximo) {
				numeroDescriptorMaximo =
						discos[cantidadDiscosConectados].descriptorSocketPDD;
			}*/
			 //BLOQUE DE ACEPTACION DE PPDs NUEVOS

				discoTrabajo =&discos[cantidadDiscosConectados];
				 if(pthread_create(discoTrabajo->tid,NULL,(void*)&pdd_thread,(void*)discoTrabajo)){
				 perror("No se puedo crear el THREAD,");
				 return EXIT_FAILURE;//si llega aca no se puedo crear el thread.
				 }


			 //FIN DEL BLOQUE DE ACEPTACION DE PPDs NUEVOS
			cantidadDiscosConectados++;
		}
		if (FD_ISSET(descriptorPFS, &descriptoresParaEscribirCopia)) {
			//puedo escribirle al PFS
		}
		if (FD_ISSET(descriptorPFS, &descriptoresExcepCopia)) {
			//se corto la conexion con el PFS?
		}
		if (FD_ISSET(descriptorPFS, &descriptoresParaLeerCopia)) {
			//el PFS me envia algo
		}
		/*for (int j = 0; j == cantidadDiscosConectados; j++) {
			if (FD_ISSET(discos[j].descriptorSocketPDD,
					&descriptoresParaLeerCopia)) {
				//el disco[j] me envia algo
			}
			if (FD_ISSET(discos[j].descriptorSocketPDD,
					&descriptoresParaEscribirCopia)) {
				//le puedo escribir al disco[j] o
			}
			if (FD_ISSET(discos[j].descriptorSocketPDD,
					&descriptoresExcepCopia)) {
				//se perdio la conexion con disco[j]
			}
		}*/

		int i;
		//loop de tratamiento de peticiones ,sincronizacion de discos y aceptacion de discos nuevos


		{ //BLOQUE DE TRATAMIENTO DE PEDIDOS
			ped = (PEDIDO*) (cola_primero(colaEntrada));
			cola_sacarDeCola(colaEntrada);
			if (ped->operacion == ESCRITURA) {
				//enviar a las colas de todos los discos.
			}
			if (ped->operacion == ESCRITURA_REFLEJO) {
				for (i = 1; i == CANTIDAD_DISCOS; i++) {
					//fijarse en la cola de pedidos de ese disco si ya no hay un pedido original a el sector destino
					//si lo hay no lo pongo, si no lo hay si lo pongo
				}
			}
			if (ped->operacion == LECTURA) {
				//FIJARSE Q DISCO TIENE LA COLA MAS CHICA Y MANDARLE EL PEDIDO (DE LOS YA REFLEJADOs)
			}
			if (ped->operacion > 3) { //PARA LAS LECTURAS QUE SE HACEN PARA LUEGO REFLEJAR
				//el numero de operacion menos 3 da el numero de disco(la posicion en el vector de discos.
				//FIJARSE Q DISCO TIENE LA COLA MAS CHICA Y MANDARLE EL PEDIDO (DE LOS YA REFLEJADOs)
				//
			}
		} //FIN DEL BLOQUE DE TRATAMIENTO DE PEDIDOS
	}
}

void pdd_thread(void *arg){
	DISCO infoDisco =*(DISCO*) arg;

	//aca hago un select para ver si puedo leer o escrivir con timeval asi alterno conun trywait del semaforo de las colas
}
